package concurrent.lock;

import java.util.concurrent.atomic.AtomicReference;

/**
 * 各种锁的学习：
 *   1.公平锁和非公平锁：
 *            1.公平锁：多个线程按照申请锁的顺序获取锁，类似排队打饭
 *            2.非公平锁： 获取锁的顺序不是申请锁的顺序，有可能造成优先级反转或者线程饥饿现象（吞吐量比公平锁大）
 *            实现：ReentrantLock实现： 不传递参数时候是非公平锁，传递boolean的时候是公平锁
 *   2.可重入锁（递归锁）： 线程可以进入任何一个拥有锁的同步代码块
 *           实现：synchronize 和ReentrantLock都可以实现
 *   3.自旋锁：（Unsafe +cas）:
 *          尝试获取锁的线程不会立即阻塞，而是采用循环的方式去获取锁，这样做的好处是减少上下文的切换。缺点是循环会消耗CPU
 *
 *   4.独占锁（写锁）/共享锁（读锁）/互斥锁
 *          独占锁：该线程只能被一个线程所持有。对Synchronized 和ReentrantLock 都是独占锁
 *          共享锁：是指锁可以被多个线程持有  ReentrantReadWriteLock  其读锁是共享锁，写锁是独占锁
 *
 *
 *   5.死锁：
 *      两个或者两个以上进程执行过程中，因为争夺资源而造成一种相互等待的现象，如果没有外力干涉，他们无法再执行下去
 *      产生死锁原因：
 *             1.系统资源不足
 *             2.进程运行推进顺序不适合（资源独占、不可抢占、保持请求、循环等待）
 *             3.资源分配不当
 *
 *             4.查看是否有死锁：
 *                     jps 类似linux ps -ef
 *                     jstack  跟踪堆栈信息工具  （JVM工具）  (Found 1 deadlock.)
 *
 */
public class Lock_Study {


    //原子引用
    AtomicReference<Thread>  threadAtomicReference=new AtomicReference<>();

    public static void main(String[] args) throws InterruptedException {
        Lock_Study  lockStudy=new Lock_Study();

        new Thread(()->{
           lockStudy.myLock();
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lockStudy.myUnlock();
        },"A").start();


        Thread.sleep(2);


        new Thread(()->{
            lockStudy.myLock();
            System.out.println( Thread.currentThread().getName()+"启动");
            lockStudy.myUnlock();
        },"B").start();


        System.out.println(Thread.currentThread().getName()+"线程要启动");


        //创建死锁
        DealLock.dealLockMethod();
    }

    /**
     * 自己实现一个自旋锁  加锁
     * B线程进来发现threadAtomicReference持有A锁，不是null,进入循环自旋。
     */
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"\t come in");
        //自旋  线程第一次进来。原子引用为null,线程加入成功。 就不进入While循环
        while (!threadAtomicReference.compareAndSet(null, thread)){


        }
    }

    /**
     * 自己实现一个自旋锁  解锁
     */
    public void myUnlock(){
        Thread thread=Thread.currentThread();
        //将当前线程设置为null ,已经用完啦
        threadAtomicReference.compareAndSet(thread, null);
    }


    static class  DealLock{
        //创建两个对象
        static Object a=new Object();
        static Object b=new Object();
        public static void dealLockMethod(){
            new Thread(()->{

                synchronized (a){
                    System.out.println(Thread.currentThread().getName()+"持有锁a,试图获取锁b");
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (b){
                    System.out.println(Thread.currentThread().getName()+"持有锁b");
                }
                }
            },"threadA").start();


            new Thread(()->{

                synchronized (b){
                    System.out.println(Thread.currentThread().getName()+"获取锁b");

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (a){
                        System.out.println(Thread.currentThread().getName()+"获取锁a");

                    }
                }
            },"threadB").start();
        }

    }

}
